package android.remotematrixclient.objclient;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;

import android.remotematrixclient.objclient.CommandWrap;


/**
 * La clase <code>Sender</code> genera un servicio de envío de objetos. Este 
 * proceso se realiza una vez cada cierto tiempo, actualmente 10ms, 
 * transmitiiendo todos los objetos que se hayan colocado en la cola de salida 
 * <code>outbound</code>, limpiándola una vez son enviados los elementos.
 * 
 * Esta clase extiende de la clase <code>TimerTask</code>, que ejecuta una 
 * tarea como un hilo, utilizando un temporizador que se vence cada cierta 
 * cantidad de milisegundos. En la versión actual el temporizador se ejecuta 
 * cada 10ms, esto es para evitar que un mensaje espere por mucho tiempo a ser
 * enviado.
 * 
 * @author Rafael Asprilla
 *
 */
public class Sender extends TimerTask {

	/**
	 * Flujo de objetos de salida.
	 */
	private ObjectOutputStream out;
	
	/**
	 * Lista enlazada de los objetos tipo <code>CommandWrap</code> de salida.
	 */
	private LinkedList<CommandWrap> outbound;
	
	/**
	 * Temporizador para el envío de datos.
	 */
	private Timer tmr;
	
	/**
	 * Constructor de la clase <code>Sender</code>.
	 * @param client
	 * Socket UDP/TCP de la conexión con el servicio.
	 */
	public Sender(Socket client){
		try {
			out = new ObjectOutputStream(client.getOutputStream());
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
		tmr = new Timer();
		tmr.schedule(this, 10, 10);
		outbound = new LinkedList<CommandWrap>();
	}
	
	/**
	 * Cancela el temporizador de envío y cierra la conexión con el 
	 * servicio de envío de objetos.
	 */
	public void close(){
		tmr.cancel();
		try {
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * Agrega un objeto de tipo <code>CommandWrap</code> a la lista enlazada de
	 * objetos de salida. Este proceso agrega el commando al final de la lista.
	 * 
	 * @param obj
	 * Objeto de tipo <code>CommandWrap</code> a ser enviado.
	 */
	public void set(CommandWrap obj){
		outbound.add(obj);
	}
	
	/**
	 * Permite agregar varios objetos de tipo <code>CommandWrap</code> a la 
	 * lista de objetos a la misma vez. Este proceso agrega el conjunto en el 
	 * mismo orden al final de la lista.
	 * 
	 * @param objs
	 * Conjunto de objetos de tipo <code>CommandWrap</code> a ser enviados.
	 */
	public void set(Collection<CommandWrap> objs){
		outbound.addAll(objs);
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		while(outbound.size() > 0){
			try {
				out.writeObject(outbound.remove());
				out.reset();
			} catch (IOException e) {
				System.err.println("I/O Error while sending data");
			}
		}
	}
}

